Skip to content

security: tighten configuration scope for SEC-200#965

Open
EhabY wants to merge 1 commit into
mainfrom
security/scope-hardening-sec-200
Open

security: tighten configuration scope for SEC-200#965
EhabY wants to merge 1 commit into
mainfrom
security/scope-hardening-sec-200

Conversation

@EhabY
Copy link
Copy Markdown
Collaborator

@EhabY EhabY commented May 19, 2026

Summary

Closes the SEC-200 attack path where a malicious .vscode/settings.json could override security-sensitive Coder settings — most notably the two command-execution settings (coder.headerCommand, coder.tlsCertRefreshCommand) called out in the original report.

The fix is metadata-only: each affected setting gets "scope": "machine". VS Code itself drops workspace and folder values for machine-scoped settings, so the malicious workspace value never reaches our code. No runtime guard is needed.

Also relaxes the release workflow so a fix can be cut from a release branch (paired with the release/v1.14.6 branch off v1.14.5).

Why machine and not window (the default)

VS Code's default scope is window, which means workspace and folder settings.json can override the user setting. That's precisely the SEC-200 attack vector. Any setting whose value can cause command execution, redirect network traffic, swap credentials, or substitute the CLI binary must not be controllable by a project file — only by the user who installed the extension.

Why machine and not application

Both application and machine block workspace/folder overrides, so both close SEC-200. The differences:

Scope Settable in Synced via Settings Sync? Per-machine override
application User settings only Yes No
machine User OR per-machine remote settings No Yes

We pick machine because most of these settings are inherently machine-specific:

  • OS-dependent shell strings — a Windows cmd.exe /c … headerCommand would sync over to a Mac via Settings Sync (application) and silently break.
  • Filesystem pathsbinaryDestination, tlsCertFile, tlsKeyFile, tlsCaFile, proxyLogDirectory are absolute paths that differ per machine.
  • Network configproxyBypass, tlsAltHost depend on the local network environment.

machine keeps the security guarantee while letting per-machine values stay per-machine, including via VS Code's Remote SSH user-level settings.

Settings updated

Setting Scope Why it's sensitive
coder.headerCommand machine Runs an external shell command (SEC-200)
coder.tlsCertRefreshCommand machine Runs an external shell command (SEC-200)
coder.binarySource machine URL the Coder CLI is downloaded from
coder.binaryDestination machine Filesystem path of the executed CLI binary
coder.disableSignatureVerification machine Toggles CLI signature verification
coder.enableDownloads machine Force-enables downloads in restricted environments
coder.sshFlags machine SSH flags accept -o ProxyCommand=… (exec)
coder.globalFlags machine Flags applied to every CLI invocation
coder.tlsCertFile machine TLS client certificate path
coder.tlsKeyFile machine TLS client key path
coder.tlsCaFile machine TLS CA path (workspace-controlled CA → MITM)
coder.tlsAltHost machine Hostname override for TLS verification
coder.insecure machine Disables TLS host verification
coder.proxyLogDirectory machine Arbitrary write path
coder.proxyBypass machine Routes traffic around the proxy
coder.defaultUrl machine Default Coder deployment URL
coder.autologin machine Combined with defaultUrl could auto-login elsewhere
coder.useKeyring machine Credential-storage preference

Already machine: coder.sshConfig.

Settings deliberately left workspace-overridable (no security risk, project-local override is legitimate): coder.networkThreshold.latencyMs, coder.httpClientLogLevel, coder.disableNotifications, coder.disableUpdateNotifications, coder.experimental.oauth, coder.telemetry.level, coder.telemetry.local.

CI change

Drops the Verify tag is on main step from .github/workflows/release.yaml so a security fix can be cut from a release branch (e.g. release/v1.14.6 off v1.14.5) without first having to merge everything sitting on main.

Companion PR

A second PR cuts the same fix as v1.14.6 off the v1.14.5 tag for users on the stable channel. This PR delivers the change on main; it lands under ## Unreleased and will be folded into the next normal release.

Test plan

  • pnpm typecheck — clean
  • pnpm lint — clean
  • pnpm test — 1670 passed / 1 skipped, no regressions
  • Manual: open a workspace with a .vscode/settings.json setting coder.headerCommand; confirm VS Code reports it as unsettable at workspace scope and the value is ignored.

@EhabY EhabY self-assigned this May 19, 2026
@EhabY EhabY requested a review from jdomeracki-coder May 19, 2026 15:54
@jdomeracki-coder
Copy link
Copy Markdown
Contributor

Does the job security wise ✅
I think a UX focused validation is warranted as well

cc: @matifali, @zenithwolf1000

@EhabY
Copy link
Copy Markdown
Collaborator Author

EhabY commented May 20, 2026

Currently those 18 settings have been moved from window to machine but there are 6 settings that can be moved into the application scope so they could be synced:

  • coder.defaultUrl — preferred Coder deployment URL
  • coder.autologin — boolean preference
  • coder.useKeyring — credential-storage preference
  • coder.insecure — TLS verification preference
  • coder.disableSignatureVerification — signature-check preference
  • coder.enableDownloads — download-toggle preference

Does it make sense to move these into the application scope since it's a better fit (not OS-specific nor per-machine) and can be synced?

@EhabY
Copy link
Copy Markdown
Collaborator Author

EhabY commented May 20, 2026

Fair but a lot of these settings are applied prior to establishing an SSH connection and thus it'd be very difficult to set them on the remote machine workspace and have it work consistently

Mark security-sensitive settings so workspace and folder `settings.json`
can no longer override them. VS Code itself drops workspace/folder values
for these settings, closing a path where a malicious workspace could
redirect command execution (`coder.headerCommand`,
`coder.tlsCertRefreshCommand`), swap the CLI binary or its source, inject
CLI/SSH flags, substitute TLS material, or override identity and
credential-storage settings.

Path-, command-, and network-dependent settings use `scope: machine`
(per-machine, not synced via Settings Sync). User-wide preferences
(`coder.defaultUrl`, `coder.autologin`, `coder.useKeyring`,
`coder.insecure`, `coder.disableSignatureVerification`,
`coder.enableDownloads`) use `scope: application`, which preserves
Settings Sync across machines while still blocking workspace overrides.

Bumps to 1.14.6 to match the v1.14.6 tag cut from `release/v1.14.6`.
@EhabY EhabY force-pushed the security/scope-hardening-sec-200 branch from 3d3a976 to 4112657 Compare May 21, 2026 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants